package Readers;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

//import jxl.Sheet;
//import jxl.Workbook;
import NWPackage.Calculations;
import NWPackage.OneSettingDistMatrix;
import NWPackage.ProbabilityCell;
import NWPackage.RealVoteCell;
import ProbabilitiesCalcs.DynamicProbCalc;
import Writers.MsgLog;
import org.apache.poi.hssf.usermodel.HSSFSheet;
//import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
//import org.apache.poi.hssf.usermodel.HSSFRow;
//import org.apache.poi.hssf.usermodel.HSSFCell;
import java.io.*; 
//import java.util.Iterator;

public class ExcelInputs extends Inputs{
	
	private final String THIS_FOLDER = System.getProperty("user.dir")+"\\";
	private int MC_LOOPS = 200;
	private String inputFile;
	private int numCandidates;
	@SuppressWarnings("unused")
	private int numVotes;
	private int numAgents;
	private List<String> agents = new ArrayList<String>();
	private List<String> dynamicCandidates;
	private OneSettingDistMatrix inputMatrix;
	//private Workbook w;
	private HSSFWorkbook w;
	private File inputWorkbook;
	private ProbabilityCell[] allprobabilities = null;
	private RealVoteCell[] realVoteInputMatrix;
	private boolean isSimulated = false;
	private String dataType = "";
	private int huristic;

	 
	 	
	 
	public ExcelInputs(String inputFile,String testFolder, Integer huristic, Integer loops) throws Exception
	{
		this.inputFile = inputFile;
		this.MC_LOOPS = loops;
		this.huristic = huristic;
		inputWorkbook = new File(THIS_FOLDER+testFolder+"\\"+inputFile);
		try {
			read();
		} catch (Exception e) {
			MsgLog.write_to_init("Error in reading the Excel File");
		}
	}
	
	 	
	//used for netflix
	private void read () throws Exception {						
		try{
			w = new HSSFWorkbook(new FileInputStream(inputWorkbook));
			//get the first sheet
			HSSFSheet sheet = w.getSheetAt(0);
			//get the Inputs:
			numAgents = (int)sheet.getRow(0).getCell(1).getNumericCellValue();
			numCandidates = (int)sheet.getRow(1).getCell(1).getNumericCellValue();
			numVotes = (int)sheet.getRow(2).getCell(1).getNumericCellValue();
			
			//check if this is a simulated data
			//isSimulated = sheet.getRow(3).getCell(1).getRichStringCellValue().getString().equals("S") ? true:false ;
			dataType = sheet.getRow(3).getCell(1).getRichStringCellValue().getString();
			if (dataType.toLowerCase().equals("n")){
				//read the netflix probs - into 'inputMatrix'
				readInputMatrix_Netflix();
				dynamicCandidates = inputMatrix.getCandidatesList();
				agents = new ArrayList<String>(inputMatrix.getVoters());
			}
			else if (dataType.toLowerCase().equals("s")){
				 //read the Simulated probs - into 'allprobabilities'
				readInputMatrix_Simulated();
				dynamicCandidates = Arrays.asList(allprobabilities[0].getCandidates());
				//agents is getting filled inside the function
			}
			else if (dataType.toLowerCase().equals("sushi")) // equals 'Sushi'
			{
				readInputMatrix_Susi();
				dynamicCandidates = Arrays.asList(allprobabilities[0].getCandidates());
			}
			else
			{
				//trow exception - read methode unknow
				throw new Exception("please specify one of the reading methods: 'N'-Netflix, 'S'-Simulated, 'Sushi'-probs for each permutation" );
			}
			//read the real votes matrix from Excel
			readRealVotesMatrix();
			
			
		}
		catch (Exception e)
		{
			MsgLog.write_to_init(e.getMessage());
			System.out.println(e.getMessage());
			throw e;
			
		}
		
	}


	private void readInputMatrix_Susi() throws Exception {
		MsgLog.write_to_init("Reading the probs directly from Excel  - simulated cells");
		int permutationsCells = Calculations.calcCandidatesPermutationsNPR(numCandidates);
		allprobabilities = new ProbabilityCell[numAgents*permutationsCells];
		int index = 0;
		HSSFSheet sheet = w.getSheetAt(1);
		//loop over all the agents
		for (int agent_index = 1; agent_index <= numAgents; agent_index++) {
			String agentName = String.valueOf(sheet.getRow(index+1).getCell(0).getNumericCellValue());
			agents.add(agentName);
			//loop over all permutations
			for (int i = 0; i < permutationsCells; i++) {
				//read the permutation cells
				int lastCell = sheet.getRow(index+1).getPhysicalNumberOfCells();
				List<String> candidates = readList(sheet,index+1);
				//read the probability
				double probability = sheet.getRow(index+1).getCell(lastCell-1).getNumericCellValue();
				
				ProbabilityCell newCell = new ProbabilityCell(agentName, probability, candidates);
				allprobabilities[index] = newCell;
				allprobabilities[index].setIndex(index);
				index++;
			}
		}
		
	}
	//create order by '<'
	private List<String> readList(HSSFSheet sheet, int rowNumber) {
		String[] permutation = new String[numCandidates];
		for (int cellIndex = 1; cellIndex <= numCandidates; cellIndex++  ) {
			permutation[cellIndex-1] = sheet.getRow(rowNumber).getCell(cellIndex).getStringCellValue();
		}
		return Arrays.asList(permutation);
	}

	private void readRealVotesMatrix() throws Exception{
		MsgLog.write_to_init("Reading Real Vote Matrix from file");
		realVoteInputMatrix = new RealVoteCell[numAgents];
		int index = 0;
		HSSFSheet sheet = w.getSheetAt(2);
		for (int agent_cand_index = 1; agent_cand_index <= numAgents; agent_cand_index++) {
			String agentName = String.valueOf(sheet.getRow(agent_cand_index).getCell(0).getNumericCellValue());
			//loop over all votes
			List<String> candidates = new ArrayList<String>();
			for (int vote_index = 1; vote_index < sheet.getRow(agent_cand_index).getPhysicalNumberOfCells(); vote_index++) {
				candidates.add(String.valueOf((int)(sheet.getRow(agent_cand_index).getCell(vote_index).getNumericCellValue())));
			}
			realVoteInputMatrix[index] = new RealVoteCell(agentName, index, candidates);
			index++;
		}
	}

	private void readInputMatrix_Netflix() throws Exception {
		MsgLog.write_to_init("Reading the input matrix from file");
		inputMatrix = new OneSettingDistMatrix();
		
		HSSFSheet sheet = w.getSheetAt(1);
		//loop over all the agents/candidates
		for (int agent_cand_index = 1; agent_cand_index < sheet.getPhysicalNumberOfRows(); agent_cand_index++) {
			String agentName = String.valueOf(sheet.getRow(agent_cand_index).getCell(0).getNumericCellValue());
			String candidate = String.valueOf((int)(sheet.getRow(agent_cand_index).getCell(1).getNumericCellValue()));
			
			//loop over all the votes
			List<String> votes = new ArrayList<String>();
			for (int vote_index = 2; vote_index < sheet.getRow(agent_cand_index).getPhysicalNumberOfCells(); vote_index++) {
				votes.add(String.valueOf(sheet.getRow(agent_cand_index).getCell(vote_index).getNumericCellValue()));
			}
			
			inputMatrix.addVotesToAgent(agentName,candidate,votes);
		}
		
	}
	
	private void readInputMatrix_Simulated()throws Exception {
		MsgLog.write_to_init("Reading the probs directly from Excel  - simulated cells");
		allprobabilities = new ProbabilityCell[numAgents*Calculations.calcCandidatesPermutationsNPR(numCandidates)];
		int index = 0;
		HSSFSheet sheet = w.getSheetAt(1);
		//loop over all the agents/candidates
		
		for (int agent_index = 1; agent_index < sheet.getPhysicalNumberOfRows(); agent_index++) {
			String agentName = String.valueOf(sheet.getRow(agent_index).getCell(0).getNumericCellValue());
			agents.add(agentName);
			
			//read all the probs for each permutation
			for (int prob_index = 1; prob_index < sheet.getRow(agent_index).getPhysicalNumberOfCells(); prob_index++) {
				double probability = sheet.getRow(agent_index).getCell(prob_index).getNumericCellValue();
				List<String> candidates  = Arrays.asList(sheet.getRow(0).getCell(prob_index).getRichStringCellValue().getString().split(","));
				ProbabilityCell newCell = new ProbabilityCell(agentName, probability, candidates);
				allprobabilities[index] = newCell;
				allprobabilities[index].setIndex(index);
				index++;
			}
		}
	}

	private void MatrixProbabilities()throws Exception {
		//MsgLog.write("Calculating the Initial probabilities permutations cells");
		allprobabilities = new ProbabilityCell[numAgents*Calculations.calcCandidatesPermutationsNPR(numCandidates)];
		List<List<String>> allPermutations = Calculations.GetPermutations(dynamicCandidates);
		//for each voter  / permutations - calc the probability for this permutation
		int index = 0;
		for (String agent : agents) {
			for (int i = 0; i < allPermutations.size(); i++) {
				//find and calc each permutation using the 'ProbabilitiesCalcs Algo
				ProbabilityCell newCell = DynamicProbCalc.DynamicProbCalcFunc(agent,allPermutations.get(i),inputMatrix.clone());
				//MsgLog.write(newCell.candidatesToString());
				allprobabilities[index] = newCell;
				allprobabilities[index].setIndex(index);
				index++;
			}
			//MsgLog.write("end agent");
		}
	}

	@Override
	public RealVoteCell[] realVotesMatrix() {
		return realVoteInputMatrix;
	}
	
	public ProbabilityCell[] getMatrixProbabilities()
	{
		if (allprobabilities == null)
			try {
				MatrixProbabilities();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				System.out.println("ERROR in excelInput");
				e.printStackTrace();
			}
		return Clone(allprobabilities);
	}

	private ProbabilityCell[] Clone(ProbabilityCell[] allprobabilities2) {
		ProbabilityCell[] clone = new ProbabilityCell[allprobabilities.length];
		for (int i = 0; i < allprobabilities.length; i++) {
			clone[i] = allprobabilities[i].clone();
		}
		return clone;
	}

	@Override
	public String[] getCandidates() {
		String[] strArray = new String[dynamicCandidates.size()];
		dynamicCandidates.toArray(strArray);
		return strArray;
	}

	@Override
	public List<String> getDynamicCandidates() {
		return dynamicCandidates;
	}

	@Override
	public int getNumCandidates() {
		return this.numCandidates;
	}

	@Override
	public String[] getAgents() {
		String[] array = new String[this.agents.size()];
		this.agents.toArray(array);
		return array;
	}

	@Override
	public int getNumAgents() {
		return this.numAgents;
	}

	@Override
	public int getMonteCarloRandomProcess() {
		return this.MC_LOOPS;
	}

	@Override
	public int getBordaMaxValue() {
		return this.numCandidates;
	}

	@Override
	public int getBordaMinValue() {
		return BORDA_MIN_VALUE;
	}
	@Override
	public String getFileName()
	{
		return this.inputFile;
	}
	@Override
	public int getHuristic()
	{
		return this.huristic;
	}


}
